package thread;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
import java.util.function.Consumer;
import java.util.function.Supplier;

/**
 * 从测试结构可以得知：在原子类中：【LongAddr】的速度明显快于【AtomicLong】。
 *      原理：LongAddr底层采用【Cell数组的形式】，这样在多线程累加的时候，出现冲突的次数就会明显小于【AtomicLong】对象。
 *          因为【数组的累加，那么线程就可以映射到不同的数组中完成】，但是【AtomicLong的累加，只能操作一个对象，这样出现冲突的情况会大大增加】。
 *      注意：LongAddr的缺点：那就是在并发自增的结果获取中，也就是调用【sum方法】，可能获取的值，不是一个准确的值，它是一个大致的值，因为会出现别的cell增加的情况。
 */
public class LongAddrTest {

    public static void main(String[] args) {
        //使用LongAddr
        for (int i = 0; i < 5; i++) {
            demo(() -> new LongAdder(), adder -> adder.increment());
        }

        //使用AtomicLong
        for (int i = 0; i < 5; i++) {
            demo(() -> new AtomicLong(), adder -> adder.getAndIncrement());
        }
    }

    private static <T> void demo(Supplier<T> adderSupplier, Consumer<T> action) {
        T adder = adderSupplier.get();

        long start = System.nanoTime();

        List<Thread> ts = new ArrayList<>();
        // 40 个线程，每人累加 50 万
        for (int i = 0; i < 40; i++) {
            ts.add(new Thread(() -> {
                for (int j = 0; j < 500000; j++) {
                    action.accept(adder);
                }
            }));
        }
        ts.forEach(t -> t.start());

        ts.forEach(t -> {
            try {
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });
        long end = System.nanoTime();
        System.out.println(adder + " cost:" + (end - start)/1000_000);
    }
}
